package com.lf.mykotlin.function

/**
 * @date: 2022/12/29
 *
 * https://juejin.cn/post/6844903969349697544
 * https://book.kotlincn.net/text/lambdas.html
 */
class MyLambda {

    /*
        lambda 表达式总是括在花括号中， 完整语法形式的参数声明放在花括号内，并有可选的类型 标注， 函数体跟在一个 -> 符号之后。
        如果推断出的该 lambda 的返回类型不是 Unit ，那 么该 lambda 主体中的最后一个（或可能是单个）表达式会视为返回值。

        {参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}

        ｛（形参列表）->
            ／／零条到多条可执行语句
         }

     */

    //箭头，映射作用；
    //箭头左边，映射输入参数的列表；
    //箭头右边，映射的输出。
    val sum = { x: Int, y: Int -> x + y }


    fun test(){
        sum(2, 3)
    }


    /*
        1. 无参数的情况 ：
            val/var 变量名 = { 操作的代码 }
    */
    val test = {
        println("无参数")
    }

    /*
        2. 有参数的情况
            val/var 变量名 : (参数的类型，参数类型，…) -> 返回值类型 = {
                参数1，参数2，… -> 操作参数的代码
            }
            可等价于
            // 此种写法：即表达式的返回值类型会根据操作的代码自推导出来。
            val/var 变量名 = { 参数1 ： 类型，参数2 : 类型, … -> 操作参数的代码 }
     */

    fun test2(a : Int , b : Int) : Int{
        return a + b
    }

    // lambda
    val test2 : (Int , Int) -> Int = {
            a , b -> a + b
    }

    // 或者
    val test3 = {
            a : Int , b : Int -> a + b
    }

    fun test21(a: Int) : Int {
        return a + 2;
    }

    val test21 : (Int) -> Int = {
        a -> a + 2
    }

    val test22 = {
        a : Int -> a + 2
    }


    /*
        3. lambda表达式作为函数中的参数的时候，这里举一个例子：
        fun test(a : Int, 参数名 : (参数1 ： 类型，参数2 : 类型, … ) -> 表达式返回类型){
            …
        }
     */
    fun test4(a : Int , b : Int) : Int {
        return a + b
    }

    fun sum(num1 : Int , num2 : Int) : Int {
        return num1 + num2
    }
    // 调用
    fun testParmFun() {
        test4(10,sum(3,5)) // 结果为：18
    }


    /*
       4. 传递末尾的 lambda 表达式
       按照 Kotlin 惯例，如果函数的最后一个参数是函数，那么作为相应参数传入的 lambda 表达式可以放在圆括号之外
       如果该 lambda 表达式是调用时唯一的参数，那么圆括号可以完全省略：
     */
    fun test5(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int {
        return a + b.invoke(3,5)
    }

    fun test6(a: (num1: Int, num2: Int) -> Int): Int {
        return a.invoke(3, 2)
    }


    fun test23(a: Int, b: (Int) -> Int) : Int {
        return a + b.invoke(2)
    }

    fun test24(b: (Int) -> Int) : Int {
        return b.invoke(2)
    }

    // 调用
    fun testLambda() {
        test5(10) {
            num1: Int, num2: Int ->  num1 + num2
        }

        test6 { num1, num2 -> num1 + num2 }

        test23(2) {
            it + 3
        }

        test24 {
            it + 3
        }


        var list = listOf("123", "lisi", "zhangsan")
        var string = list.maxByOrNull { it.length }
    }



    // 5. 在上面的方法中 build:StringBuilder.()->Unit就是一个带接受者的Lambda 表达式，它的声明语法格式是：
    //  调用者类型.(参数类型)->返回值类型

    fun createString(build:StringBuilder.()->Unit):String {
        val stringBuilder=StringBuilder()
        build(stringBuilder)
        return stringBuilder.toString()
    }

    fun testLambda3() {
        var string = createString {
            append("")
            append("ddd")
        }
    }
}